﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using mebc2.reflection;

namespace mebc2
{
    public class Board
    {
        private MetaData _metaData;

        public Board()
        {
            _metaData = new MetaData()
                            {
                                Id = this.GetHashCode().ToString(),
                                Type = this.GetType(),

                                InputPins = new List<Type>(),
                                Wires = new List<Wire>(),
                                OutputPins = new List<Type>()
                            };
        }


        public void RedirectInput<T>(Board board, object consumer) { RedirectInput<T>(board, "Process", consumer, "Process"); }
        public void RedirectInput<T>(Board board, string boardInputPinName, object consumer, string inputPinName)
        {
            Console.WriteLine("this.{0} |({1}) {2}.{3}", boardInputPinName, typeof(T).Name, consumer.GetType().Name, inputPinName);
            ((IList<Type>) _metaData.InputPins).Add(typeof (T));


            var boardInputPin = board.GetType().GetField("_" + boardInputPinName, BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
            if (boardInputPin == null)
                boardInputPin = board.GetType().GetField(boardInputPinName, BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);

            boardInputPin.SetValue(board, (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), consumer, inputPinName));
        }



        public void CaptureOuput<T>(object producer, object board) { CaptureOuput<T>(producer, "Result", board, "Result"); }
        public void CaptureOuput<T>(object producer, string outputPinName, object board, string boardOutputPinName)
        {
            Console.WriteLine("{0}.{1} |({2}) this.{3}", producer.GetType().Name, outputPinName, typeof(T).Name, boardOutputPinName);
            ((IList<Type>)_metaData.OutputPins).Add(typeof(T));

            var outputPinEvent = producer.GetType().GetEvent("Result");
            outputPinEvent.AddEventHandler(producer, (Action<T>)(x =>
                                                                     {
                                                                         var outputEvent = (Action<T>)board.GetType().GetField("Result", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(board);
                                                                         outputEvent(x);
                                                                     }));
        }



        public void Wire<T>(object producer, object consumer) { Wire(producer, "Result", (Action<T>)Delegate.CreateDelegate(typeof(Action<T>), consumer, "Process")); }
        public void Wire<T>(object producer, Action<T> consumerPin) { Wire(producer, "Result", consumerPin); }
        public void Wire<T>(object producer, string outputPinName, Action<T> consumerPin)
        {
            var outputPinEvent = producer.GetType().GetEvent(outputPinName);
            outputPinEvent.AddEventHandler(producer, consumerPin);

            Console.WriteLine("{0}.{1} |({2}) {3}.{4}",
                              producer.GetType().Name,
                              outputPinName,
                              typeof(T).Name,
                              consumerPin.Target.GetType().Name,
                              consumerPin.Method.Name);

        }


        public MetaData GetMetaData()
        {
            throw new NotImplementedException();
        }
    }
}
